#include "audiostatusmonitor.h"
#include "ui_audiostatusmonitor.h"

#include "toolutils.h"
#include "Sliderdialog.h"

#include <QMediaPlayer>
#include <QVideoWidget>
#include <QVideoSink>
#include <QVideoFrame>
#include <QImage>
#include <QPainter>

#include <QMouseEvent>
#include <QTimer>

namespace {
    constexpr int TIME_SECOND = 1000; //ms
    constexpr int TIME_STEP = 5000;   // ms
}

audioStatusMonitor::audioStatusMonitor(SVideoWidget* video, QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::audioStatusMonitor)
    , mVideoWidget(video)
{
    setAttribute(Qt::WA_DeleteOnClose);
    ui->setupUi(this);
    Init();
    ConnectAll();
}

audioStatusMonitor::~audioStatusMonitor()
{
    delete ui;
}

void audioStatusMonitor::Init()
{
    InitThumbnailPreviewUi();
    this->setStyleSheet(ToolUtils::ReadStyleSheet(":/qss/MointorQButton.qss"));
    ui->sliderProgress->setMouseTracking(true);
    // playSound
    // 1 ~ 100, step == 1
    auto sToolTip = new SliderDialog(ui->pushButtonPlaySound);
    sToolTip->SetLabelSuffix("%");
    sToolTip->SetSliderMinValue(0);
    sToolTip->SetSliderMaxValue(100);
    sToolTip->SetSliderStep(1);
    ui->pushButtonPlaySound->SetToolTips(sToolTip);
    // playRate
    // 0.25 ~ 3.0, step == 0.25 // 由于slider只支持int型，所以需要转换
    auto rToolTip = new SliderDialog(ui->pushButtonPlayRate);
    rToolTip->SetSliderMinValue(1);
    rToolTip->SetSliderMaxValue(12);
    rToolTip->SetSliderStep(1);
    rToolTip->SetValueConversion(4);
    rToolTip->SetLabelSuffix("x");
    ui->pushButtonPlayRate->SetToolTips(rToolTip);

    UpdateUI();
}

void audioStatusMonitor::InitThumbnailPreviewUi()
{
    if (mVideoWidget->PlayerType() != "video") {
        return;
    }

    mPreviewTimer = new QTimer(this);
    mPreviewTimer->setInterval(200);
    mPreviewPlayer = new QMediaPlayer(this);
    mPreviewPlayer->setSource(mVideoWidget->GetUrl());
    mPreviewPlayer->setVideoOutput(new QVideoWidget);
    mPreviewPlayer->play();
    mPreviewPlayer->pause();
    mThumbnailPreview = new QLabel(this);
    mThumbnailPreview->setWindowFlags(Qt::ToolTip | Qt::FramelessWindowHint);  // 设置为工具提示窗口
    mThumbnailPreview->setFixedSize(160, 90);
    mThumbnailTimeLabel = new QLabel(mThumbnailPreview);
    mThumbnailTimeLabel->setStyleSheet(
        "QLabel {"
        "   color: white;"
        "   background-color: rgba(0, 0, 0, 128);"
        "   padding: 2px;"
        "}"
        );
    mThumbnailTimeLabel->setAlignment(Qt::AlignCenter);
    mThumbnailPreview->hide();
    ui->sliderProgress->installEventFilter(this);
    connect(mPreviewTimer, &QTimer::timeout, mThumbnailPreview, &QLabel::hide);
}

void audioStatusMonitor::ConnectAll()
{
    connect(mVideoWidget, &SVideoWidget::PlayerSourceChanged, mPreviewPlayer, &QMediaPlayer::setSource);
    connect(mVideoWidget, &SVideoWidget::LoadMp3DataFinished, this, &audioStatusMonitor::UpdateUI);
    connect(ui->sliderProgress, &QSlider::sliderPressed, this, &audioStatusMonitor::PressProgressSlider);
    connect(ui->sliderProgress, &QSlider::sliderReleased, this, &audioStatusMonitor::ReleaseProgressSlider);

    connect(ui->pushButtonPlaySwitch, &QPushButton::clicked, mVideoWidget, &SVideoWidget::PlayOrPause);
    connect(ui->pushButtonPlayMod, &QPushButton::clicked, mVideoWidget, &SVideoWidget::ChangePlayerLoop);
    connect(ui->pushButtonPlaySound, &QPushButton::clicked, this, &audioStatusMonitor::ClickButtonPlaySound);
    connect(ui->pushButtonPlayRate,&QPushButton::clicked, this, &audioStatusMonitor::ClickButtonPlayRate);
    connect(ui->pushButtonForward, &QPushButton::clicked, this, &audioStatusMonitor::ClickButtonForward);
    connect(ui->pushButtonBackward, &QPushButton::clicked, this, &audioStatusMonitor::ClickButtonBackward);

    connect(mVideoWidget, &SVideoWidget::PlayerPositionChanged, this, &audioStatusMonitor::UpdateCurrentTime);
    connect(mVideoWidget, &SVideoWidget::PlayerStatusChanged, this, &audioStatusMonitor::UpdateButtonSwitch);
    connect(mVideoWidget, &SVideoWidget::PlayerLoopChanged, this, &audioStatusMonitor::UpdateButtonMod);
    connect(mVideoWidget, &SVideoWidget::PlayerVolumeChanged, this, &audioStatusMonitor::UpdateButtonSound);

    // playSoundButton inner
    const auto sToolTip = qobject_cast<SliderDialog*>(ui->pushButtonPlaySound->ToolTips());
    connect(sToolTip, &SliderDialog::SliderValueChanged, this, [this](int value) {
        mVideoWidget->SetPlayerVolume(static_cast<float>(value) / 100);
    });
    connect(this, &audioStatusMonitor::ButtonSoundClicked, sToolTip, &SliderDialog::SetValue);

    // playRateButton inner
    const auto rToolTip = qobject_cast<SliderDialog*>(ui->pushButtonPlayRate->ToolTips());
    connect(rToolTip, &SliderDialog::SliderValueChanged, this, [this](int value) {
        mVideoWidget->SetPlayerRate(static_cast<float>(value) / 4);
    });
}

void audioStatusMonitor::UpdateUI()
{
    auto totalTime = mVideoWidget->GetTotalTime();
    auto second = totalTime / TIME_SECOND;
    ui->labelTotalTime->setText(QString::asprintf("%02lld : %02lld", second / 60, second % 60));
    ui->sliderProgress->setMinimum(0);
    ui->sliderProgress->setMaximum(totalTime);
    UpdateButtonSwitch(mVideoWidget->IsPlaying());
    UpdateButtonMod(mVideoWidget->IsLoop());
    UpdateCurrentTime(mVideoWidget->GetCurrentTime());
    // playSoundButton inner
    const auto sToolTip = qobject_cast<SliderDialog*>(ui->pushButtonPlaySound->ToolTips());
    sToolTip->SetValue(mVideoWidget->GetVolume() * 100);
    // playRateButton inner
    const auto rToolTip = qobject_cast<SliderDialog*>(ui->pushButtonPlayRate->ToolTips());
    rToolTip->SetValue(mVideoWidget->GetRate() * 4);
}

void audioStatusMonitor::UpdateButtonSwitch(bool isPlaying)
{
    if (isPlaying) {
        ui->pushButtonPlaySwitch->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::MediaPlaybackPause));
    } else {
        ui->pushButtonPlaySwitch->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::MediaPlaybackStart));
    }
}

void audioStatusMonitor::UpdateButtonMod(bool isLoop)
{
    if (isLoop) {
        ui->pushButtonPlayMod->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::MediaPlaylistRepeat));
    } else {
        ui->pushButtonPlayMod->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::MediaPlaylistShuffle));
    }
}

void audioStatusMonitor::UpdateCurrentTime(qint64 currentTime)
{
    if (mProgressSliderPressed) {
        return;
    }
    auto second = currentTime / TIME_SECOND;
    ui->labelCurrentTime->setText(QString::asprintf("%02lld : %02lld", second / 60, second % 60));
    ui->sliderProgress->setValue(currentTime);
}

void audioStatusMonitor::UpdateButtonSound(float volume)
{
    if (volume > .8) {
        ui->pushButtonPlaySound->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::AudioVolumeHigh));
    } else if (volume > .4) {
        ui->pushButtonPlaySound->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::AudioVolumeMedium));
    } else if (volume > .0) {
        ui->pushButtonPlaySound->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::AudioVolumeLow));
    } else {
        ui->pushButtonPlaySound->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::AudioVolumeMuted));
    }
}

void audioStatusMonitor::PressProgressSlider()
{
    mProgressSliderPressed = true;
    connect(ui->sliderProgress, &QSlider::sliderMoved, this, [this](int value){
        auto second = value / TIME_SECOND;
        ui->labelCurrentTime->setText(QString::asprintf("%02d : %02d", second / 60, second % 60));
    });
}

void audioStatusMonitor::ReleaseProgressSlider()
{
    mProgressSliderPressed = false;
    UpdateCurrentTime(ui->sliderProgress->sliderPosition());
    mVideoWidget->SetPlayerPosition(ui->sliderProgress->sliderPosition());
    disconnect(ui->sliderProgress, &QSlider::sliderMoved, this, nullptr);
}

void audioStatusMonitor::ClickButtonBackward()
{
    mVideoWidget->SetPlayerPosition(
        mVideoWidget->GetCurrentTime() - TIME_STEP < 0 ? 0 : mVideoWidget->GetCurrentTime() - TIME_STEP);
}

void audioStatusMonitor::ClickButtonForward()
{
    mVideoWidget->SetPlayerPosition(
        mVideoWidget->GetCurrentTime() + TIME_STEP > mVideoWidget->GetTotalTime() ? mVideoWidget->GetTotalTime() : mVideoWidget->GetCurrentTime() + TIME_STEP);
}

void audioStatusMonitor::ClickButtonPlaySound()
{
    const auto currentVolume = mVideoWidget->GetVolume();
    if (currentVolume > 0) {
        mVideoWidget->SetPlayerVolume(.0);
        emit ButtonSoundClicked(0);
    } else {
        mVideoWidget->SetPlayerVolume(1.);
        emit ButtonSoundClicked(100);
    }
}

void audioStatusMonitor::ClickButtonPlayRate()
{

}

bool audioStatusMonitor::eventFilter(QObject *watched, QEvent *event)
{
    if (watched != ui->sliderProgress) {
        return QWidget::eventFilter(watched, event);
    }

    if (event->type() != QEvent::MouseMove && event->type() != QEvent::Leave) {
        return QWidget::eventFilter(watched, event);
    }

    if (event->type() == QEvent::Leave) {
        mPreviewTimer->start();
    }

    if (event->type() == QEvent::MouseMove) {
        if (mPreviewTimer->isActive()) {
            mPreviewTimer->stop();
            mThumbnailPreview->hide();
        }
        auto mouseEvent = dynamic_cast<QMouseEvent*>(event);
        // 获取进度条的全局位置
        QPoint sliderPos = ui->sliderProgress->mapToGlobal(QPoint(0, 0));
        // 计算预览窗口位置
        int previewX = mouseEvent->globalPosition().toPoint().x() - mThumbnailPreview->width() / 2;
        int previewY = sliderPos.y() - mThumbnailPreview->height() - 5; // 始终在进度条上方5像素
        // 更新预览位置
        mThumbnailPreview->move(previewX, previewY);

        if (mPreviewPlayer->isPlaying()) {
            mPreviewPlayer->pause();
        }

        // 计算鼠标位置对应的视频时间
        double ratio = static_cast<double>(mouseEvent->pos().x()) / ui->sliderProgress->width();
        qint64 progress = ratio * mVideoWidget->GetTotalTime();
        mPreviewPlayer->setPosition(progress);
        // qDebug() << "event->type() == QEvent::MouseMove, frame valid is " << (mPreviewPlayer->videoSink()->videoFrame().isValid() == true);

        QTimer::singleShot(50, this, [this, progress]() {
            QVideoSink* sink = mPreviewPlayer->videoSink();
            if (sink == nullptr) {
                return;
            }

            QVideoFrame frame = sink->videoFrame();
            if (!frame.isValid()) {
                qDebug() << "mThumbnailPreview, !frame.isValid()";
                return;
            }

            if (!frame.map(QVideoFrame::ReadOnly)) {
                qDebug() << "mThumbnailPreview, Frame map failed";
                return;
            }

            auto image = frame.toImage();
            if (image.isNull()) {
                qDebug() << "mThumbnailPreview, image.isNull()";
                return;
            }
            image = image.scaled(mThumbnailPreview->width(), mThumbnailPreview->height(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
            // 创建previewImage
            auto previewImage = QImage(mThumbnailPreview->size(), QImage::Format_ARGB32);
            previewImage.fill(Qt::black);
            // 居中绘制预览图
            QPainter painter(&previewImage);
            int x = (previewImage.width() - image.width()) / 2;
            int y = (previewImage.height() - image.height()) / 2;
            painter.drawImage(x, y, image);
            // 将图片和文字添加到label上面，并显示label
            mThumbnailTimeLabel->move(
                (mThumbnailPreview->width() - mThumbnailTimeLabel->width()) / 2,
                mThumbnailPreview->height() - mThumbnailTimeLabel->height());
            mThumbnailTimeLabel->setText(QString::asprintf("%02lld:%02lld", progress / 1000 / 60, progress / 1000 % 60));
            mThumbnailPreview->setPixmap(QPixmap::fromImage(previewImage));
            mThumbnailPreview->show();
        });
    }
    return QWidget::eventFilter(watched, event);
}
